﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Microsoft.Practices.ServiceLocation;
using Microsoft.Practices.SharePoint.Common.Configuration;
using Microsoft.Practices.SharePoint.Common.ServiceLocation;
using Microsoft.Practices.SharePoint.Common.Logging;

using SPaDevToolkit.Extensions;

namespace SPaDevToolkit.Diagnostics
{
    public static class AreaManager
    {
        public static DiagnosticsAreaCollection ConfiguredAreas
        {
            get
            {
                IConfigManager configMgr = SharePointServiceLocator.GetCurrent().GetInstance<IConfigManager>();
                DiagnosticsAreaCollection configuredAreas = new DiagnosticsAreaCollection(configMgr);
                return configuredAreas;
            }
        }

        public static bool AreaExists(string areaName)
        {
            return ConfiguredAreas[areaName] != null;
        }

        public static DiagnosticsArea GetArea(string areaName)
        {
            return ConfiguredAreas[areaName];
        }

        public static DiagnosticsArea AddArea(string areaname)
        {
            DiagnosticsAreaCollection configuredAreas = ConfiguredAreas;
            DiagnosticsArea area = configuredAreas[areaname];
            if (area == null)
            {
                area = new DiagnosticsArea(areaname);
                configuredAreas.Add(area);
                configuredAreas.SaveConfiguration();
            }
            return area;
        }

        public static DiagnosticsCategory AddCategory(string areaName, string categoryName, bool forceArea)
        {
            DiagnosticsAreaCollection configuredAreas = ConfiguredAreas;
            DiagnosticsArea area = configuredAreas[areaName];
            if (area == null)
                if (forceArea)
                    area = AddArea(areaName);
                else
                    throw new ArgumentException("Area " + areaName + " does not exist");

            DiagnosticsCategory category = area.DiagnosticsCategories[categoryName];
            if (category == null)
            {
                category = new DiagnosticsCategory(categoryName);
                area.DiagnosticsCategories.Add(category);
                configuredAreas.SaveConfiguration();
            }

            return category;
       }

        public static void RemoveArea(string areaName)
        {
            DiagnosticsAreaCollection configuredAreas = ConfiguredAreas;
            DiagnosticsArea area = configuredAreas[areaName];
            if (area != null)
            {
                configuredAreas.Remove(area);
                configuredAreas.SaveConfiguration();
            }
        }

        public static void ConfigureAreas(string areaConfigurationPath, bool ensureWindowsEventSource)
        {
            try
            {
                if (string.IsNullOrEmpty(areaConfigurationPath))
                    throw new ArgumentNullException("areaConfiguration file path not specified.");

                XDocument doc = XDocument.Load(areaConfigurationPath);

                var areasXml = doc.Root.Element("Areas").Elements("Area");
                DiagnosticsAreaCollection configuredAreas = ConfiguredAreas;
                foreach (XElement areaXml in areasXml)
                {
                    string areaName = areaXml.GetAttributeValue("AreaName");
                    DiagnosticsArea area = configuredAreas[areaName];
                    if (area == null)
                    {
                        area = new DiagnosticsArea(areaName);
                        configuredAreas.Add(area);
                    }

                    //Configure categories
                    var categoriesXml = areaXml.Elements("Category");
                    ConfigureCategories(area, categoriesXml);
                }
                configuredAreas.SaveConfiguration();

                if (ensureWindowsEventSource)
                    DiagnosticsAreaEventSource.EnsureConfiguredAreasRegistered();
            }
            catch (Exception ex)
            {
                Logger.WriteException(ex, "Error configuring diagnostic areas");
            }
        }

        private static void ConfigureCategories(DiagnosticsArea area, IEnumerable<XElement> categoriesXml)
        {
            foreach (var categoryXml in categoriesXml)
            {
                string categoryName = categoryXml.GetAttributeValue("CategoryName");
                DiagnosticsCategory category = area.DiagnosticsCategories[categoryName];
                if (category == null)
                {
                    category = new DiagnosticsCategory(categoryName);
                    area.DiagnosticsCategories.Add(category);
                }
            }
        }
    }
}
